/**
 * @file
 * Dynamic vector implementation similar to STL
 */

#ifndef __VECTOR_H
#define __VECTOR_H

#ifndef __LIST_H
# error "Please include list.h before vector.h"
#endif

struct vector {
    int size;
    struct list_head items;
};

#define VECTOR_INIT(name) {0, LIST_HEAD_INIT(name.items)}

#define INIT_VECTOR(ptr) ((ptr)->size = 0, INIT_LIST_HEAD(&(ptr)->items))

/**
 * vect_size - get the size of the array
 * @vect: the vector struct
 */
#define vect_size(vect)                         \
  ((vect)->size)

/**
 * vect_empty - return true if the vector has no items
 * @vect: the vector struct
 */
#define vect_empty(vect)                        \
  ((vect)->size == 0)

/**
 * vect_push_back - add a new item at the end of the vector
 * @vect: the vector struct
 * @val: the new item to be added at the end of the vector
 */
#define vect_push_back(vect, val)                       \
  (list_add_back(val, &(vect)->items), ++(vect)->size)

/**
 * vect_push_front - add a new item at the front of the vector
 * @vect: the vector struct
 * @val: the new item to be added at the front of the vector
 */
#define vect_push_front(vect, val)                      \
  (list_add_front(val, &(vect)->items), ++(vect)->size)

/**
 * vect_pop_back - remove the last item from the list and return a reference to it
 * @vect: pointer to vector struct
 * @item: reference to store the last item in the vector
 *
 * The item is set to null in case the vector is empty
 */
#define vect_pop_back(vect, item, member) do {  \
      item = NULL;                              \
      if ((vect)->size > 0) {                                           \
          item = list_entry_prev(&(vect)->items, typeof(*(item)), member); \
          list_del(&(item)->member);                                    \
          (vect)->size--;                                               \
      }                                                                 \
  } while (0)

/**
 * vect_pop_front - remove the first item from the list and return a reference to it
 * @vect: pointer to vector struct
 * @item: reference to store the last item in the vector
 *
 * The item is set to null in case the vector is empty
 */
#define vect_pop_front(vect, item, member) do { \
      item = NULL;                              \
      if ((vect)->size > 0) {                                           \
          item = list_entry_next(&(vect)->items, typeof(*(item)), member); \
          list_del(&(item)->member);                                    \
          (vect)->size--;                                               \
      }                                                                 \
  } while (0)

/**
 * vect_back - get the last item from the list
 * @vect: pointer to vector struct
 * @item: reference to store the last item in the vector
 *
 * The item is set to null in case the vector is empty
 */
#define vect_back(vect, item, member) do {      \
      item = NULL;                              \
      if ((vect)->size > 0) {                                           \
          item = list_entry_prev(&(vect)->items, typeof(*(item)), member); \
      }                                                                 \
  } while (0)

/**
 * vect_front - get the first item from the list
 * @vect: pointer to vector struct
 * @item: reference to store the last item in the vector
 * @member: the name of the list member
 *
 * The item is set to null in case the vector is empty
 */
#define vect_front(vect, item, member) do {     \
      item = NULL;                              \
      if ((vect)->size > 0) {                                           \
          item = list_entry_next(&(vect)->items, typeof(*(item)), member); \
      }                                                                 \
  } while (0)

/**
 * vect_delete - delete the current item
 * @vect: pointer to vector struct
 * @type: the stored item type
 * @member: the name of the list member
 *
 * The current item is deleted and item is set to the next entry or null
 * if the end of the list is reached
 */
#define vect_delete(vect, item, member) do {                            \
      typeof(item) __next__ = NULL;                                     \
                                                                        \
      if (list_entry_prev(&(vect)->items, typeof(*(item)), member) != item) { \
          __next__ = list_entry_next(&(item)->member, typeof(*(item)), member); \
      }                                                                 \
      list_del(&(item)->member);                                        \
      (vect)->size--;                                                   \
      item = __next__;                                                  \
  } while (0)

/**
 * vect_begin - get the first item in the vector
 * @vect: pointer to vector struct
 * @type: the stored item type
 * @member: the name of the list member
 *
 * It is the user problem to use this macro properly
 */
#define vect_begin(vect, type, member) \
    ((vect_empty(vect)) ? NULL : list_entry_next(&(vect)->items, type, member))

/**
 * vect_next - move to the next item
 * @vect: pointer to vector struct
 * @item: reference to store the next item in the vector
 * @member: the name of the list member
 *
 * It is the user problem to use this macro properly
 */
#define vect_next(vect, item, member) \
  ((item) == NULL || (&(vect)->items == (item)->member.next) ? NULL : list_entry_next(&(item)->member, typeof(*(item)), member))

/**
 * vect_get_at - get the item with the specified index
 * @vect: pointer to vector struct
 * @item: reference to store the item at the specified index
 * @index: the index of the value 
 * @member: the name of the list member
 *
 * If the vector size is excided then null is returned
 */
#define vect_get_at(vect, index, item, member) do {     \
      int __index__ = (index);                          \
                                                        \
      item = NULL;                                      \
      if (__index__ < (vect)->size) {                                   \
          for(item = vect_begin(vect, typeof(*(item)), member); __index__>0; __index__--, item=vect_next(vect, item, member)) \
              ;                                                         \
      }                                                                 \
  } while (0)

#endif /* __VECTOR_H */
